﻿/*   
    Copyright (C) 2009 Galaktika Corporation ZAO

    This file is a part of Galaktika.BusinessMonitor
 
    Galaktika.BusinessMonitor is a free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
      
    You should have received a copy of the GNU General Public License
    along with Galaktika.BusinessMonitor.  If not, see <http://www.gnu.org/licenses/>.
  
    If GPL v.3 is not suitable for your products or company,
    Galaktika Corp provides Galaktika.BusinessMonitor under a flexible commercial license
    designed to meet your specific usage and distribution requirements.
    If you have already obtained a commercial license from Galaktika Corp,
    you can use this file under those license terms.
*/

using System;
using System.Collections.Generic;
using System.Net;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Ranet.AgOlap.Controls.ContextMenu;

namespace Galaktika.BI.Silverlight.ClientApp.Services
{
    using Galaktika.BI.Extensibility;
    using Galaktika.BI.Extensibility.Dom;
    using Galaktika.BI.Runtime;
    using Galaktika.BI.Runtime.Services;
    using Galaktika.BI.Silverlight.ClientApp.Items;
    using Galaktika.BI.Silverlight.ClientApp.Services;
    using Galaktika.BI.Silverlight.Controls;
    using System.Windows.Controls.Primitives;

    public class HistoryItem
    {
        public HistoryItem(string caption, DateTime time, string formId)
            : this(caption, time, formId, null)
        {
        }

        public HistoryItem(string caption, DateTime time, string formId, IDictionary<string, string> stateVars)
        {
            this.Caption = caption;
            this.FormId = formId;
            this.StateVariables = stateVars;
            this.Time = time;
        }

        public string Caption;
        public readonly DateTime Time;
        public readonly IDictionary<string, string> StateVariables;
        public readonly string FormId;
    }

    public class HistoryItemEventArgs : EventArgs
    {
        public HistoryItemEventArgs(
            bool isBack)
        {
            this.IsBack = isBack;
        }

        public HistoryItemEventArgs(
            bool isBack, Point point)
            : this(isBack)
        {
            this.Position = point;
        }

        public readonly bool IsBack;
        public readonly Point Position = default(Point);
    }

    public class PageNavigator : IFormNavigator, IAppManager, ITabPageFormResolver
    {
        //#region NavigateByHistoryCommand
        //private delegate bool GoMethodInvoker();
        //private class NavigateByHistoryCommand : ICommand
        //{
        //    public const string HISTORY_ITEM = "historyitem";
        //    private PageNavigator m_Manager;
        //    public NavigateByHistoryCommand(PageNavigator manager)
        //    {
        //        m_Manager = manager;
        //    }

        //    #region ICommand Members

        //    public void Invoke(IInvokeContext context)
        //    {
        //        HistoryItem hi = context.GetData(HISTORY_ITEM) as HistoryItem;
        //        if (!m_Manager.TryNavigate(hi, m_Manager.m_BackForms, new GoMethodInvoker(m_Manager.GoBack)))
        //        {
        //            m_Manager.TryNavigate(hi, m_Manager.m_ForwardForms, new GoMethodInvoker(m_Manager.GoForward));
        //        }
        //    }

        //    #endregion
        //}
        //#endregion 

        TabPageContainer tabContainer;
        private Button m_BtnGoBack;
        private Button m_BtnGoFwd;
        private Button m_MnuGoBack;
        private Button m_MnuGoForward;
        private Button m_BtnRefresh;
        private Button m_BtnReset;
        private Button m_BtnRun;
        private Button m_BtnFullScreen;
        private ToggleButton m_BtnCO;
        private ToggleButton m_BtnVars;
        //private Popup m_Popup_Back;
        //private Popup m_Popup_Forward;


        //public PageNavigator(TabPageContainer container, DataBinder binder)
        //{            
        //    tabContainer = container;
        //    tabContainer.TabPageClosed += new TabPageClosedEventHandler(tabContainer_TabPageClosed);
        //    tabContainer.SelectionChanged += new SelectionChangedEventHandler(tabContainer_SelectionChanged);
        //}

        public PageNavigator(TabPageContainer container,
            DataBinder binder,
            Button btnBack,
            Button btnForward,
            Button mnuBack,
            Button mnuForward,
            Button btnRefresh,
            Button btnReset,
            Button btnRun,
            Button btnFullScreen,
            ToggleButton btnCO,
            ToggleButton btnVars)
        {
            btnBack.IsEnabled = btnForward.IsEnabled = btnRun.IsEnabled =
                mnuBack.IsEnabled = mnuBack.IsEnabled = btnReset.IsEnabled =
                btnRefresh.IsEnabled = btnCO.IsEnabled = btnVars.IsEnabled = false;

            m_BtnGoBack = btnBack;
            m_BtnGoFwd = btnForward;
            m_MnuGoBack = mnuBack;
            m_MnuGoForward = mnuForward;
            m_BtnRun = btnRun;
            m_BtnRefresh = btnRefresh;
            m_BtnReset = btnReset;
            m_BtnFullScreen = btnFullScreen;
            m_BtnCO = btnCO;
            m_BtnVars = btnVars;
            tabContainer = container;
            tabContainer.TabPageClosed += new TabPageClosedEventHandler(tabContainer_TabPageClosed);
            tabContainer.SelectionChanged += new SelectionChangedEventHandler(tabContainer_SelectionChanged);
            m_MnuGoBack.Click += new RoutedEventHandler(m_MnuGoBack_MouseLeftButtonDown);
            m_MnuGoForward.Click += new RoutedEventHandler(m_MnuGoForward_MouseLeftButtonDown);
            m_BtnCO.Click += new RoutedEventHandler(m_BtnCO_Click);
            m_BtnVars.Click += new RoutedEventHandler(m_BtnVars_Click);
            this.ShowContextMenu += new EventHandler<HistoryItemEventArgs>(PageNavigator_ShowContextMenu);

        }

        void m_BtnVars_Click(object sender, RoutedEventArgs e)
        {
            FormView form = this.SelectedHostForm;
            if (form != null)
            {
                if (m_BtnVars.IsChecked.HasValue)
                {
                    form.IsVariablesVisible = m_BtnVars.IsChecked.Value;
                }
            }
        }

        void m_BtnCO_Click(object sender, RoutedEventArgs e)
        {
            FormView form = this.SelectedHostForm;
            if (form != null)
            {
                if (m_BtnCO.IsChecked.HasValue)
                {
                    form.IsContextWindowsVisible = m_BtnCO.IsChecked.Value;
                }
            }
        }

        CustomContextMenu m_ContextMenu = null;
        public CustomContextMenu ContextMenu
        {
            get
            {
                if (m_ContextMenu != null)
                {
                    //m_ContextMenu = ReCreateContextMenu();
                    Raise_ContextMenuCreated();
                }
                return m_ContextMenu;
            }
        }

        public event EventHandler ContextMenuCreated;
        private void Raise_ContextMenuCreated()
        {
            EventHandler handler = this.ContextMenuCreated;
            if (handler != null)
            {
                handler(this, EventArgs.Empty);
            }
        }

        public event EventHandler<HistoryItemEventArgs> ShowContextMenu;
        private void Raise_ShowContextMenu(HistoryItemEventArgs args)
        {
            EventHandler<HistoryItemEventArgs> handler = this.ShowContextMenu;
            if (handler != null)
            {
                handler(this, args);
            }
        }

        protected virtual void OnShowContextMenu(object sender, HistoryItemEventArgs args)
        {
            if (args.IsBack)
                m_ContextMenu = ReCreateContextMenu(m_BackForms);
            else
                m_ContextMenu = ReCreateContextMenu(m_ForwardForms);

            if (ContextMenu.IsDropDownOpen)
                ContextMenu.IsDropDownOpen = false;

            ContextMenu.SetLocation(args.Position);
            ContextMenu.Tag = args.IsBack;
            ContextMenu.IsDropDownOpen = true;
        }

        void m_MnuGoForward_MouseLeftButtonDown(object sender, RoutedEventArgs e)
        {
            this.OnShowContextMenu(sender, new HistoryItemEventArgs(false, m_MnuGoForward.TransformToVisual(App.CurrentApp.Root.RootControl).Transform(new Point(m_MnuGoForward.ActualWidth, m_MnuGoForward.ActualHeight))));
        }

        void m_MnuGoBack_MouseLeftButtonDown(object sender, RoutedEventArgs e)
        {
            this.OnShowContextMenu(sender, new HistoryItemEventArgs(true, m_MnuGoBack.TransformToVisual(App.CurrentApp.Root.RootControl).Transform(new Point(m_MnuGoBack.ActualWidth, m_MnuGoBack.ActualHeight))));
        }

        void PageNavigator_ShowContextMenu(object sender, HistoryItemEventArgs e)
        {
            this.OnShowContextMenu(sender, e);
        }

        private CustomContextMenu ReCreateContextMenu(Dictionary<string, Stack<HistoryItem>> forms)
        {
            CustomContextMenu contextMenu = new CustomContextMenu();
            PopulateMenuItems(contextMenu, forms);
            return contextMenu;
        }

        public void UpdateCurrentContext()
        {
            FormView hf = this.SelectedHostForm;
            if (hf != null)
            {
                //this.TabManager.SelectedPage.Image = hf.View.BrickContainer.Image;
                //if (hf.View.IsDockingDirty)
                //{
                //    hf.View.LoadDocking();
                //}
                var exe = App.CurrentApp.GetService<IExecutionContext>();
                if (exe != null)
                {
                    ((this.tabContainer.SelectedItem as TabItem).Header as TabHeader).Text =
                        exe.Parse(App.CurrentApp.Binder.GetContext(hf), hf.Text);
                }
            }
            if (System.Windows.Browser.HtmlPage.IsEnabled)
            {
                System.Windows.Browser.HtmlPage.Document.SetProperty("title", this.GetAppTitle());
                this.SetHelp(hf);
            }
            this.UpdateUserToolbars(hf);
        }

        private void UpdateUserToolbars(FormView hf)
        {
            var mainToolbar = ((Page)App.CurrentApp.Root).MainToolbar;
            if (mainToolbar != null)
            {
                var toRemove = new List<BrickUserToolbar>(mainToolbar.GetCurrentToolbars());

                if (hf != null)
                {
                    foreach (var tb in hf.Container.Toolbars)
                    {
                        if (toRemove.Contains(tb))
                        {
                            toRemove.Remove(tb);
                        }
                    }
                }

                foreach (var r in toRemove)
                {
                    mainToolbar.RemoveToolbar(r);
                }

                if (hf != null)
                {
                    foreach (var tbToAdd in hf.Container.Toolbars)
                    {
                        if (mainToolbar.IsContains(tbToAdd)) continue;

                        mainToolbar.AppendToolbar(tbToAdd);
                    }

                    var context = App.CurrentApp.Binder.GetContext(hf);
                    if (context != null)
                    {
                        mainToolbar.SetBindingContext(context);
                    }
                }
            }
        }

        internal void ShowCurrentHelp()
        {
            var fv = this.SelectedHostForm;
            if (fv != null)
            {
                var container = fv.Container;
                if (container.HelpLinks.ContainsKey(container.Name))
                {
                    HelpLinkDescriptor helpLink = container.HelpLinks[container.Name];
                    if (helpLink.UseHelp)
                    {
                        HelpManager.Show(helpLink.HelpNamespace);
                    }
                }
                else
                {
                    this.ShowGlobalHelp();
                }
            }
            else
            {
                this.ShowGlobalHelp();
            }
        }

        private void ShowGlobalHelp()
        {
            string globalHelp = ClientResources.GetGlobalValue("HelpNamespace");
            if (!string.IsNullOrEmpty(globalHelp))
            {
                HelpManager.Show(globalHelp);
            }
        }

        private void SetHelp(FormView hf)
        {
            if (HelpManager.IsVisible)
            {
                if (hf != null)
                {
                    var container = hf.Container;
                    if (container.HelpLinks.ContainsKey(container.Name))
                    {
                        HelpLinkDescriptor helpLink = container.HelpLinks[container.Name];
                        if (helpLink.UseHelp)
                        {
                            HelpManager.SetHelp(helpLink.HelpNamespace);
                        }
                    }
                }
                else
                {
                    string globalHelp = ClientResources.GetGlobalValue("HelpNamespace");
                    if (!string.IsNullOrEmpty(globalHelp))
                    {
                        HelpManager.SetHelp(globalHelp);
                    }
                }
            }
        }

        #region AppManager

        public void UpdateNavigationBar()
        {
            FormView form = this.SelectedHostForm;
            if (form != null)
            {
                //может и не надо
                bool canUpdate = true;
                Stack<HistoryItem> backForms;
                Stack<HistoryItem> forwardForms;
                m_BackForms.TryGetValue(form.UniqueId, out backForms);
                m_ForwardForms.TryGetValue(form.UniqueId, out forwardForms);

                m_BtnGoBack.IsEnabled = m_MnuGoBack.IsEnabled =
                     canUpdate && backForms.Count > 0;
                m_BtnGoFwd.IsEnabled = m_MnuGoForward.IsEnabled =
                     canUpdate && forwardForms.Count > 0;
                m_BtnRun.IsEnabled = m_BtnRefresh.IsEnabled = m_BtnReset.IsEnabled =
                    /*m_BtnFullScreen.IsEnabled =*/ true;

                //if (form.HasContextWindows)
                //{
                m_BtnCO.IsEnabled = true;
                m_BtnCO.IsChecked = form.IsContextWindowsVisible;
                //}
                //else
                //{
                //    m_BtnCO.IsChecked = false;
                //    m_BtnCO.IsEnabled = false;
                //}

                m_BtnVars.IsEnabled = true;
                m_BtnVars.IsChecked = form.IsVariablesVisible;

            }
            else
            {
                m_BtnCO.IsEnabled = false;
                m_BtnCO.IsChecked =
                m_BtnGoBack.IsEnabled = m_BtnGoFwd.IsEnabled = m_MnuGoBack.IsEnabled =
                    m_MnuGoBack.IsEnabled = m_BtnRun.IsEnabled = m_BtnRefresh.IsEnabled =
                    m_BtnReset.IsEnabled = /*m_BtnFullScreen.IsEnabled =*/
                    m_BtnVars.IsEnabled =
                    false;
            }
        }

        void tabContainer_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            m_SelectedPage = tabContainer.SelectedItem as TabPage;
            this.UpdateNavigationBar();
            this.UpdateCurrentContext();
            this.OnCurrentFormChanged();
        }

        //public void OnMenuForward_Expanded(object sender, CancelEventArgs e)
        //{
        //    if (sender is Popup)
        //    {
        //        m_Popup_Forward = sender as Popup;
        //        m_Popup_Forward.IsOpen = !m_Popup_Forward.IsOpen;
        //        if (m_Popup_Forward.IsOpen)
        //            this.PopulateMenuItems((Popup) sender, m_ForwardForms);
        //    }
        //}

        //public void OnMenuBack_Expanded(object sender, CancelEventArgs e)
        //{
        //    if (sender is Popup)
        //    {
        //        m_Popup_Back = sender as Popup;
        //        m_Popup_Back.IsOpen = !m_Popup_Back.IsOpen;
        //        if (m_Popup_Back.IsOpen)
        //            this.PopulateMenuItems((Popup) sender, m_BackForms);
        //    }
        //}

        private Dictionary<CustomContextMenu, List<object>> m_MenuItems = new Dictionary<CustomContextMenu, List<object>>();
        private void PopulateMenuItems(CustomContextMenu menu, Dictionary<string, Stack<HistoryItem>> itemsCache)
        {
            //this.BarManager.BeginUpdate();

            // Получаем список ранее созданных элементов
            //
            List<object> barItems;
            m_MenuItems.TryGetValue(menu, out barItems);
            if (barItems == null)
            {
                barItems = new List<object>();
                m_MenuItems.Add(menu, barItems);
            }

            // Удаляем прежние элементы
            //
            foreach (UIElement bi in barItems)
            {
                menu.Items.Remove(bi);
            }
            barItems.Clear();

            // Создаем новые
            //
            FormView form = this.SelectedHostForm;
            if (form != null)
            {
                Stack<HistoryItem> items;
                itemsCache.TryGetValue(form.UniqueId, out items);
                if (items != null)
                {
                    foreach (HistoryItem hi in items)
                    {
                        var caption = string.Format("{0} {1}", hi.Caption, hi.Time.ToString("HH:mm"));
                        ContextMenuItem item = new ContextMenuItem(caption);
                        //item.Height = 10;                        
                        item.ItemClick += new EventHandler(item_Click);
                        item.Tag = hi;
                        menu.AddMenuItem(item);
                        //InvokeContext context = new InvokeContext();
                        //context.SetData(NavigateByHistoryCommand.HISTORY_ITEM, hi);
                        //BarButtonItem item = new BarButtonItem(this.BarManager, string.Format("{0} {1}", hi.Caption, hi.Time.ToString("HH:mm")));
                        //barItems.Add(item);
                        //item.Tag = new KeyValuePair<ICommand, IInvokeContext>(new NavigateByHistoryCommand(this), context);
                        //this.BarManager.Items.Add(item);
                        //menu.ItemLinks.Add(item);
                    }
                }
            }

            //this.BarManager.EndUpdate();
        }

        void item_Click(object sender, EventArgs e)
        {
            var historyItem = ((sender as ContextMenuItem).Tag as HistoryItem);
            if (historyItem != null)
            {
                if (!this.TryNavigate(historyItem, m_BackForms, true))
                {
                    //m_Popup_Forward.IsOpen = false;
                    this.TryNavigate(historyItem, m_ForwardForms, false);
                    return;
                }
                //m_Popup_Back.IsOpen = false;
            }
        }

        public void ResetForm()
        {
        }

        public object CurrentForm
        {
            get
            {
                return this.SelectedHostForm;
            }
        }

        public object Owner
        {
            get
            {
                return tabContainer;
            }
        }

        public Assembly ClientAssembly
        {
            get
            {
                return ClientResources.ClientAssembly;
            }
        }

        public event EventHandler CurrentFormChanged;
        protected virtual void OnCurrentFormChanged()
        {
            if (this.CurrentFormChanged != null)
            {
                this.CurrentFormChanged(this, EventArgs.Empty);
            }
        }

        public event EventHandler SaveCurrentState;
        protected virtual void OnSaveCurrentState()
        {
            if (this.SaveCurrentState != null)
            {
                this.SaveCurrentState(this, EventArgs.Empty);
            }
        }

        public event EventHandler LoadCurrentState;
        protected virtual void OnLoadCurrentState()
        {
            if (this.LoadCurrentState != null)
            {
                this.LoadCurrentState(this, EventArgs.Empty);
            }
        }

        public string GetAppTitle()
        {
            if (this.SelectedHostForm != null)
            {
                return string.Format("{0} - {1}", ClientResources.GetGlobalValue("_$ProductName"), this.SelectedHostForm.Text);//, Localization.App_Title);
            }

            return string.Format("{0}", ClientResources.GetGlobalValue("_$ProductName"));//, Localization.App_Title);
        }
        #endregion

        #region AppEvents
        public void AppStarted()
        {
            string formId = ClientResources.GetGlobalValue("_$StartupFormId");
            if (!string.IsNullOrEmpty(formId))
            {
                NavigateTo(formId, true);
            }

            this.DoAppEvent(BrickEvent.APP_STARTED);
        }

        public void AppShutdown()
        {
            this.DoAppEvent(BrickEvent.APP_SHUTDOWN);
        }

        public void FormOpened(string formId)
        {
            this.DoAppEvent(BrickEvent.FORM_OPENED,
                new KeyValuePair<string, string>[] { new KeyValuePair<string, string>("formId", formId) });
        }

        public void FormClosed(string formId)
        {
            this.DoAppEvent(BrickEvent.FORM_CLOSED,
                new KeyValuePair<string, string>[] { new KeyValuePair<string, string>("formId", formId) });
        }

        private void DoAppEvent(string eventName)
        {
            this.DoAppEvent(eventName, new KeyValuePair<string, string>[] { });
        }

        private void DoAppEvent(string eventName, KeyValuePair<string, string>[] args)
        {
            string handlerType = ClientResources.GetGlobalValue(eventName);
            if (!string.IsNullOrEmpty(handlerType))
            {
                Type startType = ClientResources.ClientAssembly.GetType(handlerType);
                if (startType != null)
                {
                    MethodInfo method = startType.GetMethod("Invoke", BindingFlags.Public | BindingFlags.Static);
                    if (method != null)
                    {
                        this.TrySetCurrentCaller();
                        method.Invoke(null, new object[] { new SafeDictionary<string, string>(args) });
                    }
                }
            }
        }

        private void TrySetCurrentCaller()
        {
            var context = App.CurrentApp.Binder.GetContext(this.SelectedHostForm);
            if (context != null)
            {
                var impl = App.CurrentApp.GetService<IScriptEngine>() as ScriptEngineImpl;
                if (impl != null)
                {
                    impl.Caller.SetValue(null, new Galaktika.BI.Silverlight.Controls.PivotGrid.MockCaller(context));
                }
            }
        }

        #endregion

        #region IFormNavigator Members

        private Dictionary<TabPage, FormView> m_HostFormByPage = new Dictionary<TabPage, FormView>();
        private List<FormView> m_OpenedForms = new List<FormView>();
        private Dictionary<string, Stack<HistoryItem>> m_BackForms = new Dictionary<string, Stack<HistoryItem>>();
        private Dictionary<string, Stack<HistoryItem>> m_ForwardForms = new Dictionary<string, Stack<HistoryItem>>();
        private TabPage m_SelectedPage;

        public FormView SelectedHostForm
        {
            get
            {
                FormView form = null;
                //TabPage tabItem = tabContainer.SelectedItem as TabPage;
                TabPage tabItem = m_SelectedPage;
                if (tabItem != null)
                {
                    //m_SelectedPage = tabItem;
                    m_HostFormByPage.TryGetValue(tabItem, out form);
                }

                return form;
            }
        }

        public TabPage SelectedPage
        {
            get { return m_SelectedPage; }
        }

        private bool NavigateTo(
            HistoryItem item,
            bool openInNewWindow,
            bool modifyHistoryInternal,
            bool logToHistory,
            IDictionary<string, string> args)
        {
            try
            {
                tabContainer.Cursor = Cursors.Wait;
                FormView form = null;
                if (openInNewWindow)
                {
                    foreach (KeyValuePair<TabPage, FormView> hf in m_HostFormByPage)
                    {
                        if (hf.Value.Id == item.FormId)
                        {
                            tabContainer.SelectedItem = hf.Key;
                            return true;
                        }
                    }
                }

                form = this.SelectedHostForm;
                IBrickContainer container = null;
                List<string> newContext = new List<string>();
                bool needToRefresh = false;
                bool newFormOpened = false;

                if ((form == null || openInNewWindow) && !string.IsNullOrEmpty(item.FormId))
                {
                    // Пытаемся сконстуировать форму
                    form = ConstructForm(item);
                    if (form == null)
                        return false;
                    newFormOpened = true;
                    needToRefresh = true;
                }
                else
                {
                    if (!modifyHistoryInternal && logToHistory)
                    {
                        IDictionary<string, string> vars = GetVariables(form);
                    }
                    // check - if drill down by data
                    //
                    if (!string.IsNullOrEmpty(item.FormId) && form != null && form.Id != item.FormId)
                    {
                        OpenNewForm(item, form);
                        needToRefresh = true;
                        //this.FormOpened(form.Id);
                    }
                    // restore context state if any
                    //
                    if (item.StateVariables != null)// && context != null)
                    {
                        needToRefresh = RestoreContextState(item, needToRefresh);
                    }
                }
                if (!modifyHistoryInternal)
                {
                    this.UpdateNavigationBar();
                }

                if (needToRefresh)
                {
                    RefreshContext(args);
                }

                if (newFormOpened)
                {
                    this.FormOpened(form.Id);
                }

                this.UpdateCurrentContext();
                this.OnLoadCurrentState();
                this.OnCurrentFormChanged();


                return true;
            }
            catch (Exception exc)
            {
                //App.CurrentApp.LogError(exc);
                throw new ServerException(exc.Message, exc);
            }
            finally
            {
                tabContainer.Cursor = null;
            }

        }

        private void RefreshContext(IDictionary<string, string> args)
        {
            IBindingContext currentContext = App.CurrentApp.Binder.GetContext(this.SelectedHostForm);
            if (currentContext == null)
            {
                throw new UnableToResolveBindingContextException(this.SelectedHostForm);
            }

            var contextVars = this.ExtractCurrentVariables(args);
            if (contextVars.Count > 0)
            {
                var exe = App.CurrentApp.GetService<IExecutionContext>();
                if (exe != null)
                {
                    if (exe.ModifyVariables(currentContext, contextVars))
                    {
                        exe.DoDrillDown(currentContext);
                    }
                }
            }
            else
            {
                App.CurrentApp.Binder.RefreshImmediate(currentContext);
            }
        }

        private bool RestoreContextState(HistoryItem item, bool needToRefresh)
        {
            IExecutionContext exe =
                App.CurrentApp.GetService<IExecutionContext>();
            //IUserTaskManager taskManager = App.CurrentApp.GetService<IUserTaskManager>();
            // TODO: Refactor!!!
            // Восстанавливать состояния переменных из ВСЕХ контекстов
            // формы.
            if (/*taskManager != null && */exe != null)
            {
                IBindingContext context = App.CurrentApp.Binder.GetContext(this.SelectedHostForm);
                //taskManager.RunTaskAsync(
                //    Galaktika.BI.Silverlight.ClientApp.Localization.AppTask_ModifyVariables,
                //    state =>
                //    {
                if (exe.ModifyVariables(context, item.StateVariables))
                {
                    exe.DoDrillDown(context);
                }
                //});
                needToRefresh = false;
            }
            return needToRefresh;
        }

        private FormView ConstructForm(HistoryItem item)
        {
            FormView form;
            IBrickContainer container;
            container = ClientResources.GetContainer(item.FormId);
            // Форма не созана, скорее всего был введен неверный 
            // идентификатор формы
            if (container == null)
            {
                MessageBox.Show(string.Format(Galaktika.BI.Silverlight.ClientApp.Localization.Exc_FormIdNotExist,
                                              item.FormId),ClientApp.Localization.Str_Error,MessageBoxButton.OK);
                //throw new InformationalException(string.Format(Galaktika.BI.Silverlight.ClientApp.Localization.Exc_FormIdNotExist, item.FormId));
                return null;
            }
            item.Caption = container.Title;
            form = ClientResources.ConstructHostForm(new FormView(), container, item.FormId);//, newContext);
            //needToRefresh = true;

            TabPage tabItem = tabContainer.AddPage(container.Title, container.Description, form);
            tabContainer.SelectedItem = tabItem;
            m_HostFormByPage.Add(tabItem, form);

            m_OpenedForms.Add(form);
            m_BackForms.Add(form.UniqueId, new Stack<HistoryItem>());
            m_ForwardForms.Add(form.UniqueId, new Stack<HistoryItem>());

            return form;
        }

        private void OpenNewForm(HistoryItem item, FormView form)
        {
            IBrickContainer container;
            container = ClientResources.GetContainer(item.FormId);
            if (container == null)
            {
                MessageBox.Show(string.Format(Galaktika.BI.Silverlight.ClientApp.Localization.Exc_FormIdNotExist,
                                              item.FormId),ClientApp.Localization.Str_Error,MessageBoxButton.OK);
                //throw new InformationalException(string.Format(Galaktika.BI.Silverlight.ClientApp.Localization.Exc_FormIdNotExist, item.FormId));
                return;
            }
            this.DetachHelp(form);
            // в случае DrillDown контекст удаляется нами вручную
            // (в другом случае - при закрытии - контекст удаляется по form_Disposed)
            var exe = App.CurrentApp.GetService<IExecutionContext>();
            if (exe != null)
            {
                var currentContext = App.CurrentApp.Binder.GetContext(form.Id);
                var newContext2 = App.CurrentApp.Binder.GetContext(item.FormId);

                var stateVars = exe.GetStateVariables(currentContext);
                exe.ModifyVariables(newContext2, stateVars, false);
            }


            App.CurrentApp.Binder.DestroyContext(form.Id);
            this.FormClosed(form.Id);

            ClientResources.ConstructHostForm(form, container, item.FormId);
            this.AttachHelp(container, form);
        }

        private IDictionary<string, string> GetVariables(FormView form)
        {
            Stack<HistoryItem> backForms;
            Stack<HistoryItem> forwardForms;
            m_ForwardForms.TryGetValue(form.UniqueId, out forwardForms);
            m_BackForms.TryGetValue(form.UniqueId, out backForms);

            forwardForms.Clear();
            IDictionary<string, string> vars = null;
            IExecutionContext exe =
                App.CurrentApp.GetService<IExecutionContext>();

            // TODO: Refactor!!!
            // Сохранять состояния переменных из ВСЕХ контекстов
            // формы.
            if (exe != null)
            {
                var context = App.CurrentApp.Binder.GetContext(this.SelectedHostForm);
                vars = exe.GetStateVariables(context);
                backForms.Push(new HistoryItem(form.Text, DateTime.Now, form.Id, vars));
            }
            return vars;
        }

        private IDictionary<string, string> ExtractCurrentVariables(IDictionary<string, string> args)
        {
            var res = new SafeDictionary<string, string>();
            if (args != null && args.Count > 0)
            {
                var variables = App.CurrentApp.Binder.DefaultVariables;
                foreach (var kv in args)
                {
                    if (variables.IsExists(kv.Key) && !res.ContainsKey(kv.Key))
                    {
                        res.Add(kv.Key, kv.Value);
                    }
                }
            }

            return res;
        }

        public bool NavigateTo(string formId, bool openInNewWindow, bool logToHistory)
        {
            return this.NavigateTo(formId, openInNewWindow, logToHistory, null);
        }

        public bool NavigateTo(string formId, bool openInNewWindow, bool logToHistory, IDictionary<string, string> args)
        {
            return this.NavigateTo(new HistoryItem(string.Empty, DateTime.Now, formId), openInNewWindow, false, logToHistory, args);
        }

        public bool NavigateTo(IDictionary<string, string> args)
        {
            string openInNewWindow = args["openInNewWindow"];
            bool isNewWindow;
            bool.TryParse(openInNewWindow, out isNewWindow);
            return this.NavigateTo(args["formId"], isNewWindow, true, args);
        }

        public bool NavigateTo(string formId, bool openInNewWindow)
        {
            return this.NavigateTo(formId, openInNewWindow, true);
        }

        public void PushState()
        {
            this.NavigateTo(new HistoryItem(string.Empty, DateTime.Now, string.Empty), false, false, true, null);
        }

        public void PopState()
        {
            FormView form = this.SelectedHostForm;
            if (form != null)
            {
                Stack<HistoryItem> backForms;
                Stack<HistoryItem> forwardForms;
                m_BackForms.TryGetValue(form.UniqueId, out backForms);
                m_ForwardForms.TryGetValue(form.UniqueId, out forwardForms);
                if (backForms.Count > 0)
                {
                    this.NavigateTo(backForms.Pop(), false, true, true, null);
                }
                UpdateNavigationBar();
            }
        }

        private bool TryNavigate(
            HistoryItem hi,
            Dictionary<string, Stack<HistoryItem>> forms, bool back)
        {
            FormView form = this.SelectedHostForm;
            if (form != null)
            {
                Stack<HistoryItem> items;
                forms.TryGetValue(form.UniqueId, out items);
                if (items != null && items.Contains(hi))
                {
                    while (!items.Peek().Equals(hi))
                    {
                        items.Pop();
                    }

                    if (back)
                        GoBack();
                    else
                        GoForward();

                    return true;
                }
            }

            return false;
        }

        public void AttachHelp(IBrickContainer container, object rootObj)
        {
            Control root = rootObj as Control;

            if (root != null)
            {
                if (container.HelpLinks.ContainsKey(root.Name))
                {
                    this.AttachHelpInternal(container, root, root.Name);
                }

                this.AttachHelpInChildren(container, root);
            }
        }

        private void AttachHelpInChildren(IBrickContainer container, Control parent)
        {
            //foreach (Control child in parent.Controls)
            //{
            //    if (container.HelpLinks.ContainsKey(child.Name))
            //    {
            //        this.AttachHelpInternal(container, child, child.Name);
            //    }
            //    else if (container.HelpLinks.ContainsKey(parent.Name))
            //    {
            //        this.AttachHelpInternal(container, child, parent.Name);
            //    }
            //    this.AttachHelpInChildren(container, child);
            //}
        }

        private void AttachHelpInternal(IBrickContainer container, Control ctrl, string attachedHelpLinkName)
        {
            //HelpLinkDescriptor helpLink = container.HelpLinks[attachedHelpLinkName];
            //System.Windows.Forms.HelpProvider hp = m_HelpProviders[helpLink.HelpNamespace];
            //if (hp == null)
            //{
            //    m_HelpProviders[helpLink.HelpNamespace] = hp = new HelpProvider();
            //    hp.HelpNamespace = helpLink.HelpNamespace;
            //}

            //hp.SetShowHelp(ctrl, true);
            //hp.SetHelpKeyword(ctrl, helpLink.HelpKeyword);
            //hp.SetHelpNavigator(ctrl, (HelpNavigator)Enum.Parse(typeof(HelpNavigator), helpLink.HelpNavigator));
        }

        private void DetachHelp(Control root)
        {
            //foreach (HelpProvider hp in m_HelpProviders.Values)
            //{
            //    hp.ResetShowHelp(root);
            //}
            //foreach (Control ctrl in root.Controls)
            //{
            //    this.DetachHelp(ctrl);
            //}
        }

        void tabContainer_TabPageClosed(object sender, TabPageClosedEventArgs e)
        {
            FormView form = null;
            m_HostFormByPage.TryGetValue(e.TabPage, out form);
            if (form != null)
            {
                DataBinder.Current.DestroyContext(form.Id);
                this.DetachHelp(form);
                m_OpenedForms.Remove(form);
                m_BackForms.Remove(form.UniqueId);
                m_ForwardForms.Remove(form.UniqueId);
                m_HostFormByPage.Remove(e.TabPage);
            }
            this.UpdateCurrentContext();
            this.UpdateNavigationBar();
        }

        public bool GoBack()
        {
            FormView form = this.SelectedHostForm;
            if (form != null)
            {
                Stack<HistoryItem> backForms;
                Stack<HistoryItem> forwardForms;
                m_BackForms.TryGetValue(form.UniqueId, out backForms);
                m_ForwardForms.TryGetValue(form.UniqueId, out forwardForms);
                string id = form.Id;
                string caption = form.Text;
                if (backForms.Count > 0)
                {
                    IExecutionContext exe = App.CurrentApp.GetService<IExecutionContext>();
                    //IUserTaskManager taskManager = App.CurrentApp.GetService<IUserTaskManager>();
                    // TODO: Refactor!!!
                    // Сохранять состояния переменных из ВСЕХ контекстов
                    // формы.
                    if (/*taskManager != null && */exe != null)
                    {
                        IBindingContext context = App.CurrentApp.Binder.GetContext(form);
                        //taskManager.RunTaskAsync(
                        //    Galaktika.BI.Silverlight.ClientApp.Localization.AppTask_GetVariables,
                        //    state =>
                        //    {
                        HistoryItem hi = backForms.Pop();
                        IDictionary<string, string> vars = exe.GetStateVariables(context);
                        //taskManager.Dispatcher.BeginInvoke(() =>
                        //{
                        this.NavigateTo(hi, false, true, true, null);
                        forwardForms.Push(new HistoryItem(caption, DateTime.Now, id, vars));
                        this.UpdateNavigationBar();
                        //});
                        //}); 
                    }
                    return true;
                }
            }
            return false;
        }

        public bool GoForward()
        {
            FormView form = this.SelectedHostForm;
            if (form != null)
            {
                Stack<HistoryItem> backForms;
                Stack<HistoryItem> forwardForms;
                m_BackForms.TryGetValue(form.UniqueId, out backForms);
                m_ForwardForms.TryGetValue(form.UniqueId, out forwardForms);
                string id = form.Id;
                string caption = form.Text;
                if (forwardForms.Count > 0)
                {
                    IExecutionContext exe = App.CurrentApp.GetService<IExecutionContext>();
                    //IUserTaskManager taskManager = App.CurrentApp.GetService<IUserTaskManager>();

                    // TODO: Refactor!!!
                    // Сохранять состояния переменных из ВСЕХ контекстов
                    // формы.
                    if (/*taskManager != null && */exe != null)
                    {
                        var context = App.CurrentApp.Binder.GetContext(form);
                        //taskManager.RunTaskAsync(
                        //    Galaktika.BI.Silverlight.ClientApp.Localization.AppTask_GetVariables,
                        //    state =>
                        //    {
                        IDictionary<string, string> vars = exe.GetStateVariables(context);
                        HistoryItem hi = forwardForms.Pop();
                        //taskManager.Dispatcher.BeginInvoke(() =>
                        //    {
                        this.NavigateTo(hi, false, true, true, null);
                        backForms.Push(new HistoryItem(caption, DateTime.Now, id, vars));
                        this.UpdateNavigationBar();
                        //});
                        //});
                    }

                    return true;
                }
            }

            return false;
        }

        #endregion


        #region ITabPageFormResolver Members

        public FormView GetForm(TabPage tabPage)
        {
            FormView form;
            m_HostFormByPage.TryGetValue(tabPage, out form);
            return form;
        }

        #endregion
    }
}
